import React, { Component } from 'react'
import {
 Alert, Button, Form, Input, message, Select, Spin,
} from 'antd'
import { history } from '@umijs/max'
import { v4 } from 'uuid'
import FieldMapping from 'react-field-mapping'
import styles from './index.less'
import { offlineTableFields } from './api'

class FieldMap extends Component {
  constructor(props) {
    super(props)
    this.state = {
      sourceFields: [],
      targetFields: [],
      relation: [],
      partitionFields: [],
      btnSelectIndex: null,
      type: {
        Kafka: [
          'string',
          'boolean',
          'double',
          'date',
          'bytes',
        ],
        Mongodb: [
          'tinyint',
          'smallint',
          'int',
          'bigint',
          'float',
          'double',
          'decimal',
          'timestamp',
          'char',
          'string',
          'varchar',
          'date',
          'boolean',
          'binary',
        ],
        HBase: [
          'tinyint',
          'smallint',
          'int',
          'bigint',
          'float',
          'double',
          'decimal',
          'timestamp',
          'char',
          'string',
          'varchar',
          'date',
          'boolean',
          'binary',
        ],
      },
    }
    this.time = null
    this.form = React.createRef()
  }

  componentDidMount() {
    window.onresize = () => {
      clearTimeout(this.time)
      this.time = setTimeout(() => {
        const { sourceFields, targetFields, relation } = this.state
        this.setState({
          sourceFields,
          targetFields,
          relation: [],
        }, () => {
          this.setState({
            relation,
          })
        })
      }, 500)
    }
  }

  async componentWillReceiveProps(nextProps) {
    if (nextProps.data.sourceTable !== this.props.data.sourceTable || nextProps.data.targetTable !== this.props.data.targetTable) {
      const data = nextProps.data
      let targetFields = []; let sourceFields = []; let relation = []
      if (data.sourceDsType === 'Kafka' || data.sourceDsType === 'Mongodb' || data.sourceDsType === 'HBase') {
        sourceFields = []
        data && data.fieldMappings && data.fieldMappings.map((item) => {
          sourceFields.push({
            fieldName: item.sourceField,
            fieldType: item.sourceFieldType,
            key: item.sourceField,
          })
        })
      } else {
        sourceFields = await this.offlineTableFields(0, data.sourceDsId, data.sourceTable)
      }
      if (data.targetDsType === 'Kafka' || data.targetDsType === 'Mongodb' || data.targetDsType === 'HBase') {
        targetFields = []
        data && data.fieldMappings && data.fieldMappings.map((item) => {
          targetFields.push({
            fieldName: item.targetField,
            fieldType: item.targetFieldType,
            key: item.targetField,
          })
        })
      } else {
        targetFields = await this.offlineTableFields(1, data.targetDsId, data.targetTable, data)
      }
      if (data.sourceTable !== nextProps.oldData.sourceTable || data.targetTable !== nextProps.oldData.targetTable) {
        relation = []
      } else {
        relation = await this.setRelation(data)
      }

      this.setState({
        sourceFields,
        targetFields,
      }, () => {
        this.setState({
          relation,
        })
      })
    } else if (nextProps.currentStep !== this.props.currentStep) {
      const { sourceFields, targetFields, relation } = this.state
      this.setState({
        sourceFields,
        targetFields,
        relation: [],
      }, () => {
        this.setState({
          relation,
        })
      })
    }
  }

  setRelation = (data) => new Promise((resolve, reject) => {
    const relation = []
    data && data.fieldMappings && data.fieldMappings.map((item) => {
      relation.push({
        source: {
          fieldName: item.sourceField,
          fieldType: item.sourceFieldType,
          isPk: item.isSourceFieldPk,
          comment: item.comment,
          key: item.sourceField,
        },
        target: {
          fieldName: item.targetField,
          fieldType: item.targetFieldType,
          isPk: item.isTargetFieldPk,
          comment: item.comment,
          key: item.targetField,
        },
      })
    })
    resolve(relation)
  })

  offlineTableFields = (direction, dsId, tables, detail) => new Promise((resolve, reject) => {
    offlineTableFields({ direction, dsId, tables: [tables] }).then((res) => {
      if (res.status === 200) {
        const data = res.data && res.data.tables[0] && res.data.tables[0].fields
        const dataArr = []
        data && data.map((item) => {
          item.key = item.fieldName
          item.isPk = item.pk ? 1 : 0
          if (direction === 1 && !item.isPartition) {
            dataArr.push(item)
          } else if (direction === 0) {
            dataArr.push(item)
          }
        })
        if (direction === 1) {
          this.setState({
            partitionFields: res.data && res.data.tables[0] && res.data.tables[0].partitionFields || [],
          }, () => {
            const obj = {}
            const paritions = detail.paritions || []
            paritions.map((item) => {
              obj[item.fieldName] = item.fieldValue
            })
            this.form.current.setFieldsValue({
              ...obj,
            })
          })
        }
        resolve(dataArr)
      } else {
        resolve([])
      }
    })
  })

  // 同行映射
  sameLine = () => {
    const { sourceFields, targetFields } = this.state
    const len = sourceFields.length > targetFields.length
      ? targetFields.length
      : sourceFields.length
    const relation = []
    for (let i = 0; i < len; i++) {
      relation.push({
        source: {
          ...sourceFields[i],
        },
        target: {
          ...targetFields[i],
        },
      })
    }

    this.setState({
      relation,
      btnSelectIndex: 0,
    })
  }

  // 同名映射
  sameName = () => {
    const { sourceFields, targetFields } = this.state
    const relation = []
    sourceFields.map((item) => {
      targetFields.map((n) => {
        if (item.key.toLowerCase() === n.key.toLowerCase()) {
          relation.push({
            source: {
              ...item,
            },
            target: {
              ...n,
            },
          })
        }
      })
    })
    this.setState({
      relation,
      btnSelectIndex: 1,
    })
  }

  onConfirm = () => {
    const { relation } = this.state
    const fieldMappings = []
    const paritions = []
    relation && relation.map((item) => {
      fieldMappings.push({
        isSourceFieldPk: item.source.isPk,
        isTargetFieldPk: item.target.isPk,
        sourceField: item.source.fieldName,
        sourceFieldType: item.source.fieldType,
        targetField: item.target.fieldName,
        targetFieldType: item.target.fieldType,
      })
    })
    this.form.current.validateFields().then(values => {
      Object.keys(values).forEach((key) => {
        paritions.push({
          fieldName: key,
          fieldValue: values[key],
        })
      })
      this.props.currentStepChange(2, { fieldMappings, paritions })
    })
  }

  render() {
    const {
      sourceFields, targetFields, relation, btnSelectIndex, type, partitionFields,
    } = this.state
    const { sourceDsType, targetDsType } = this.props.data
    const sourceCols = [
      {
        title: '源字段',
        key: 'fieldName',
        width: '2rem',
        render: (fieldName, record) => (
          <>
            {record.pk && <i className="iconfont icon-zhujian" />}
            <span>{fieldName}</span>
          </>
        ),
      },
      { title: '类型', key: 'fieldType' },
      {
        title: '非空',
        key: 'nullable',
        width: '0.5rem',
        // render: (nullable) => (nullable ? '是' : '-'),
        render: (nullable) => (nullable ? '-' : '是'),
      },
      { title: '描述', key: 'comment' },
    ]

    const sourceColsEdit = [
      {
        title: '源字段',
        key: 'fieldName',
        render: (val, record, k) => (
          <div>
            {record.edit ? (
              <Input
                value={val}
                pl
                style={{ width: '100%', height: '.3rem' }}
                onChange={(e) => {
                  relation.map((obj) => {
                    if (obj.source.key == record.key) {
                      obj.source.fieldName = e.target.value
                      obj.source.key = e.target.value
                    }
                  })
                  record.fieldName = e.target.value
                  record.key = e.target.value
                  this.setState(
                    {
                      sourceFields: [...sourceFields],
                    },
                    () => {
                      this.setState({
                        relation: [...relation],
                      })
                    },
                  )
                }}
              />
            ) : (
              <span>{val}</span>
            )}
          </div>
        ),
      },
      {
        title: '类型',
        key: 'fieldType',
        render: (val, record, k) => (
          <div>
            {record.edit ? (
              <Select
                value={val}
                style={{ width: '100%', height: '.2rem' }}
                onChange={(value) => {
                  relation.map((obj) => {
                    if (obj.source.key == record.key) {
                      obj.source.fieldType = value
                    }
                  })
                  record.fieldType = value
                  this.setState(
                    {
                      sourceFields: [...sourceFields],
                    },
                    () => {
                      this.setState({
                        relation: [...relation],
                      })
                    },
                  )
                }}
              >
                {type[sourceDsType].map((v, index) => (
                  <Select.Option title={v} key={index} value={v}>
                    {v}
                  </Select.Option>
                ))}
              </Select>
            ) : (
              <span>{val}</span>
            )}
          </div>
        ),
      },
      {
        title: '操作',
        key: 'active',
        width: '1rem',
        render: (val, record, k) => (
          <div>
            {record.edit ? (
              <span
                style={{
                  color: '#0084FF',
                  fontSize: '.12rem',
                  cursor: 'pointer',
                  marginRight: '.05rem',
                }}
                onClick={() => {
                  if (record.fieldType && record.fieldName) {
                    record.edit = false
                    this.setState({
                      sourceFields: [...sourceFields],
                    })
                  } else {
                    message.warning('字段名或类型不能为空')
                  }
                }}
              >
                保存
              </span>
            ) : (
              <span
                style={{
                  color: '#0084FF',
                  fontSize: '.12rem',
                  cursor: 'pointer',
                  marginRight: '.05rem',
                }}
                onClick={() => {
                  record.edit = true
                  this.setState({
                    sourceFields: [...sourceFields],
                  })
                }}
              >
                编辑
              </span>
            )}
            <span
              style={{
                color: '#0084FF',
                fontSize: '.12rem',
                cursor: 'pointer',
              }}
              onClick={() => {
                const relations = [...relation]
                relation.map((obj, index) => {
                  if (obj.source.key == record.key) {
                    relations.splice(index, 1)
                  }
                })
                const data = [...sourceFields]
                data.splice(k, 1)
                this.setState(
                  {
                    sourceFields: [...data],
                  },
                  () => {
                    this.setState({
                      relation: [...relations],
                    })
                  },
                )
              }}
            >
              删除
            </span>
          </div>
        ),
      },
    ]
    return (
      <div className={styles.field_map} style={{ ...this.props.style }}>
        <div className={styles.column}>字段映射</div>
        <Alert message="您要配置来源表与目标表的字段映射关系，通过连线将待同步的字段左右相连。也可以通过同行映射、同名映射批量完成映射。" type="info" showIcon />

        <div className={styles.btn_wrap}>
          <span className={`${btnSelectIndex === 0 ? styles.on : ''}`} onClick={this.sameLine}>同行映射</span>
          <span className={`${btnSelectIndex === 1 ? styles.on : ''}`} onClick={this.sameName}>同名映射</span>
          {
            relation.length > 0 && (
              <span onClick={() => {
                this.setState({
                  relation: [],
                  btnSelectIndex: null,
                })
              }}
              >
                取消映射
              </span>
            )
          }
          {sourceDsType === 'Kafka' || sourceDsType === 'Mongodb' || sourceDsType === 'HBase' ? (
            <span onClick={() => {
              const newSourceFields = [...sourceFields]
              newSourceFields.push({
                edit: true,
                key: v4(),
              })
              this.setState({
                sourceFields: newSourceFields,
              })
            }}
            >添加来源字段
            </span>
          ) : null}
          {targetDsType === 'Kafka' || targetDsType === 'Mongodb' || targetDsType === 'HBase' ? (
            <span onClick={() => {
              const newSourceFields = [...targetFields]
              newSourceFields.push({
                edit: true,
                key: v4(),
              })
              this.setState({
                targetFields: newSourceFields,
              })
            }}
            >添加目标字段
            </span>
          ) : null}
        </div>

        <Spin spinning={false} tip="正在获取字段信息...">
          <div className={styles.field_mapping}>
            <FieldMapping
              {...{
                source: {
                  data: sourceFields,
                  columns: sourceDsType === 'Kafka' || sourceDsType === 'Mongodb' || sourceDsType === 'HBase' ? sourceColsEdit : sourceCols,
                  mutiple: false,
                },
                target: {
                  data: targetFields,
                  columns: targetDsType === 'Kafka' || targetDsType === 'Mongodb' || targetDsType === 'HBase' ? sourceColsEdit : sourceCols,
                  mutiple: false,
                },
                relation,
                // edit: !disabled,
                onChange: (relations) => {
                  this.setState({
                    relation: relations,
                  })
                },
              }}
            />
          </div>
          {partitionFields && partitionFields.length ? <div className={styles.column}>分区字段</div> : null}
          <div style={{ width: '5rem', marginBottom: '1.5rem' }}>
            <Form
              labelCol={{ span: 5 }}
              wrapperCol={{ span: 19 }}
              ref={this.form}
            >
              {partitionFields && partitionFields.map((item) => (
                <Form.Item
                  label={item.fieldName}
                  name={item.fieldName}
                  rules={[{ required: true, message: '请输入分区值' }]}
                >
                  <Input />
                </Form.Item>
              ))}
            </Form>
          </div>
        </Spin>

        <div className={styles.edit_footer}>
          <Button onClick={() => { history.push('/dataIntegrate/offline/manager') }} className={styles.edit_btn}>取消</Button>
          <Button
            className={styles.edit_btn}
            onClick={() => {
              this.props.returnStep(0)
            }}
            type="primary"
          >上一步
          </Button>
          <Button className={styles.edit_btn} onClick={this.onConfirm} type="primary">下一步</Button>
        </div>
      </div>
    )
  }
}

export default FieldMap
